package net.yeah.mickey_zhouyou.util.fcs.elem;

import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.script.ScriptContext;

import net.yeah.mickey_zhouyou.util.fcs.ReaderOverException;
import net.yeah.mickey_zhouyou.util.fcs.ReaderWrapper;
import net.yeah.mickey_zhouyou.util.fcs.SyntaxException;
import net.yeah.mickey_zhouyou.util.fcs.serialize.IConvertor;

public class ConditionCompare extends ConditionSelector {
	private enum Compare {
		GT, LT, EQ, GE, LE
	}

	private Compare comp;
	private Obj leftObj;
	private Obj rightObj;

	public static ConditionCompare create(ReaderWrapper reader)
			throws IOException {
		Obj leftObj = Obj.create(reader);
		Compare comp = readCompare(reader);
		Obj rightObj = Obj.create(reader);
		try {
			char b = reader.lookNotBlank();
			if (b == ')') {
				ConditionCompare cc = new ConditionCompare();
				cc.leftObj = leftObj;
				cc.rightObj = rightObj;
				cc.comp = comp;
				return cc;
			}
		} catch (ReaderOverException e) {
		}
		throw new SyntaxException("读取条件表达式失败", reader.getCurrentRow(),
				reader.getCurrentColumn());
	}

	private static Compare readCompare(ReaderWrapper reader) throws IOException {
		try {
			char b = reader.readNotBlank();
			switch (b) {
			case '<':
				b = reader.look();
				if (b == '=') {
					b = reader.read();
					return Compare.LE;
				} else
					return Compare.LT;
			case '>':
				b = reader.look();
				if (b == '=') {
					b = reader.read();
					return Compare.GE;
				} else
					return Compare.GT;
			case '=':
				b = reader.read();
				if (b == '=')
					return Compare.EQ;
				break;
			}
		} catch (ReaderOverException e) {
		}
		throw new SyntaxException("读取比较运算符失败", reader.getCurrentRow(),
				reader.getCurrentColumn());
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object select(Object obj, IConvertor objConvertor,
			ScriptContext context) {
		if (obj == null)
			return null;
		Field field = null;
		if (obj.getClass().isArray()) {
			int len = Array.getLength(obj);
			if (len == 0)
				return null;
			List<Object> res = new ArrayList<Object>();
			for (int i = 0; i < len; ++i) {
				Object o = Array.get(obj, i);
				Object lo = null, ro = null;
				if (this.leftObj != null)
					lo = this.leftObj.asRightValue(objConvertor, field,
							context, o);
				if (this.rightObj != null)
					ro = this.rightObj.asRightValue(objConvertor, field,
							context, o);
				if (lo == null && ro == null) {
					if (this.comp == Compare.EQ)
						res.add(o);
				} else if (lo != null && ro != null && lo instanceof Comparable) {
					Comparable<Object> c = (Comparable<Object>) lo;
					int r = c.compareTo(ro);
					if ((r == 0 && this.comp != Compare.GT && this.comp != Compare.LT)
							|| (r < 0 && (this.comp == Compare.LT || this.comp == Compare.LE))
							|| (r > 0 && (this.comp == Compare.GT || this.comp == Compare.GE)))
						res.add(o);
				}
			}
			return res;
		} else if (obj instanceof List) {
			List<Object> list = (List<Object>) obj;
			if (list.size() == 0)
				return null;
			List<Object> res = new ArrayList<Object>();
			for (Object o : list) {
				Object lo = null, ro = null;
				if (this.leftObj != null)
					lo = this.leftObj.asRightValue(objConvertor, field,
							context, o);
				if (this.rightObj != null)
					ro = this.rightObj.asRightValue(objConvertor, field,
							context, o);
				if (lo == null && ro == null) {
					if (this.comp == Compare.EQ)
						res.add(o);
				} else if (lo != null && ro != null && lo instanceof Comparable) {
					Comparable<Object> c = (Comparable<Object>) lo;
					int r = c.compareTo(ro);
					if ((r == 0 && this.comp != Compare.GT && this.comp != Compare.LT)
							|| (r < 0 && (this.comp == Compare.LT || this.comp == Compare.LE))
							|| (r > 0 && (this.comp == Compare.GT || this.comp == Compare.GE)))
						res.add(o);
				}
			}
			return res;
		} else {
			Object lo = null, ro = null;
			if (this.leftObj != null)
				lo = this.leftObj.asRightValue(objConvertor, field, context,
						obj);
			if (this.rightObj != null)
				ro = this.rightObj.asRightValue(objConvertor, field, context,
						obj);
			if (lo == null && ro == null) {
				if (this.comp == Compare.EQ)
					return obj;
			} else if (lo != null && ro != null && lo instanceof Comparable) {
				Comparable<Object> c = (Comparable<Object>) lo;
				int r = c.compareTo(ro);
				if ((r == 0 && this.comp != Compare.GT && this.comp != Compare.LT)
						|| (r < 0 && (this.comp == Compare.LT || this.comp == Compare.LE))
						|| (r > 0 && (this.comp == Compare.GT || this.comp == Compare.GE)))
					return obj;
			}
		}
		return null;
	}
}
